package code.example.base.reflect.method;

import code.example.base.reflect.BikeProducer;
import code.example.tool.LogFactory;

import java.lang.reflect.*;

public class TestMethod {

    public void showType(Type type){
        if(type == null){

        }else  if(ParameterizedType.class.isAssignableFrom(type.getClass())){
            ParameterizedType parameterizedType = (ParameterizedType) type;
            String typeName = type.getTypeName();
            LogFactory.getLog().info("ParameterizedType:"+typeName);
            Type[] types = parameterizedType.getActualTypeArguments();
            for(Type param:types){
                showType(param);
            }
            Type rawType =  parameterizedType.getRawType();
            showType(rawType);
        }else if(Class.class.isAssignableFrom(type.getClass())){
            Class classz = (Class)type;
            if(Object.class.equals(classz)){
                return;
            }
            String name =  classz.getCanonicalName();
            LogFactory.getLog().info("className:"+name);
        }else if(TypeVariable.class.isAssignableFrom(type.getClass())){
            TypeVariable typeVariable = (TypeVariable)type;
            String name = typeVariable.getName();
            LogFactory.getLog().info("type:"+name);
        }
    }

    private void showMethodName(Method method){
        String methodName = method.getName();
        LogFactory.getLog().info("methodName:"+methodName);
        LogFactory.getLog().info("");
    }
    private void showReturnType(Method method){
        Type type = method.getGenericReturnType();
        LogFactory.getLog().info("return type:");
        showType(type);
        LogFactory.getLog().info("");
    }
    private void showModifier(Method method){
        int  modifiers  =method.getModifiers();
        LogFactory.getLog().info("modifier:"+modifiers);
        LogFactory.getLog().info("");
    }
    private void showParameter(Method method){
        Parameter[] parameters = method.getParameters();
        for(int i=0;i<parameters.length;i++){
            Parameter parameter = parameters[i];
            String parameterName = parameter.getName();
            LogFactory.getLog().info("show parameter "+i+":");
            Type type = parameter.getParameterizedType();
            LogFactory.getLog().info("parameterName:"+parameterName);
            LogFactory.getLog().info("parameterType:");
            showType(type);

            LogFactory.getLog().info("");
        }
    }

    private void showMethodDeclare(Method method){

        StringBuilder stringBuilder = new StringBuilder();

        stringBuilder.append(method.getModifiers());
        stringBuilder.append(" ");
        stringBuilder.append(method.getGenericReturnType().getTypeName());
        stringBuilder.append(" ");
        stringBuilder.append(method.getName());
        stringBuilder.append("(");
        Parameter[] parameters = method.getParameters();
        for(int i=0;i<parameters.length;i++){
            if(i>0){
                stringBuilder.append(",");
            }
            Parameter parameter = parameters[i];
            stringBuilder.append(parameter.getParameterizedType().getTypeName());
            stringBuilder.append(" ");
            stringBuilder.append(parameter.getName());
        }
        stringBuilder.append(")");
        LogFactory.getLog().info(stringBuilder.toString());

    }
    public void publicMethod(Object obj){
        LogFactory.getLog().info("------------------ public method ----------------------");
        Method  [] methods = obj.getClass().getMethods();
        for(int i=0;i<methods.length;i++){
            Method method = methods[i];
            showMethodDeclare(method);
        }
        LogFactory.getLog().info("-------------------------------------------------------");
    }
    public void declareMethod(Object obj ){
        LogFactory.getLog().info("------------------ declare method ----------------------");
        Method  [] methods = obj.getClass().getDeclaredMethods();
        for(int i=0;i<methods.length;i++){
            Method method = methods[i];
            showMethodDeclare(method);
        }
        LogFactory.getLog().info("-------------------------------------------------------");
    }
    public void callPrivateMethod(Object obj ) throws Exception {
        String methodName="getJobDescription";
        Method method = obj.getClass().getDeclaredMethod(methodName,null);
        method.setAccessible(true);
        Object result = method.invoke(obj,null);
        LogFactory.getLog().info(" invoke private method "+methodName+", return value="+result);

    }
    public Object generate(){
        BikeProducer bikeProducer = new BikeProducer();
        bikeProducer.setCompanyName("大灯车厂");
        bikeProducer.setName("张三");
        return bikeProducer;
    }

    public void test(){
        try {
            Object obj = generate();
            publicMethod(obj);
            declareMethod(obj);
            callPrivateMethod(obj);
        }catch (Exception e){
            LogFactory.getLog().error(e);
        }
    }
    public static void main(String args []){
        new TestMethod().test();
    }
}
